/**
 * 
 */
package com.alstudio.module.xmpp.EventHandler.network;

import android.text.TextUtils;

import com.alstudio.app.ALLocalEnv;
import com.alstudio.app.VersionConfig;
import com.alstudio.event.ALEventDeliver;
import com.alstudio.module.xmpp.distributor.distributor.DistributorEvent;
import com.alstudio.module.xmpp.distributor.distributor.DistributorManager;
import com.alstudio.module.xmpp.protocol.xmpp.ALXmppAdapter;
import com.alstudio.module.xmpp.protocol.xmpp.ALXmppException;
import com.alstudio.module.xmpp.protocol.xmpp.data.ALXmppConnectionState;
import com.alstudio.module.xmpp.protocol.xmpp.data.ALXmppData;
import com.alstudio.module.xmpp.protocol.xmpp.data.ALXmppEventType;
import com.alstudio.module.xmpp.protocol.xmpp.packact.ALMessage;
import com.alstudio.module.xmpp.protocol.xmpp.util.openstream.OpenStreamUtil;
import com.alstudio.module.xmpp.protocol.xmpp.util.xmlcreator.iq.register.CheckEmailIQCreator;
import com.alstudio.module.xmpp.protocol.xmpp.util.xmlcreator.iq.register.CheckThirdPartLoginStateIQCreator;
import com.alstudio.module.xmpp.protocol.xmpp.util.xmlcreator.iq.register.RegisterIQCreator;
import com.alstudio.module.xmpp.request.ALUiXmppRequestEvent;
import com.alstudio.pojo.ALXmppEvent;
import com.alstudio.pojo.module.local.LocalConfigure;
import com.alstudio.pojo.module.server.ServerInfo;
import com.alstudio.utils.account.ALAccount;
import com.alstudio.utils.android.net.ALConnectionManager.ALConnectionType;
import com.alstudio.utils.log.ALLog;

/**
 * 
 * xmpp连接管理
 * 
 * @author alonso lee
 * 
 */
public class ALXmppConnetionWrapper extends BaseALXmppLoginWrapper {
	// 是否已经连接过分发器
	private boolean isGetDistributorData = false;

	/**
	 * 
	 */
	public ALXmppConnetionWrapper(ALAccount accont) {
		// TODO Auto-generated constructor stub
		this.localAccount = accont;
		ALEventDeliver.getDefaultAlEventDeliver().register(this);
		if (localAccount == null) {
			throw new ALXmppException("账号信息对象不能为空");
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * registerALXmppAdapter
	 * (com.alstudio.module.xmpp.protocol.xmpp.ALXmppAdapter)
	 */
	@Override
	public void registerALXmppAdapter(ALXmppAdapter adapter) {
		// TODO Auto-generated method stub
		this.mDefaultXmppAdapter = adapter;
		isXmppAdapterValidate();
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * release()
	 */
	@Override
	public void release() {
		// TODO Auto-generated method stub
		ALEventDeliver.getDefaultAlEventDeliver().unregister(this);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeUIRequest(com.alstudio.pojo.ALLocalData)
	 */
	@Override
	public synchronized void invokeUIRequest(Object request) {
		// TODO Auto-generated method stub
		ALUiXmppRequestEvent event = (ALUiXmppRequestEvent) request;
		ALLog.d("收到UI请求事件" + event.getRequestTye());

		switch (event.getRequestTye()) {
		case XMPP_LOGIN_REQUEST:
			ALLog.d("ui请求登陆");
			isLoginWithId = localAccount.isLoginWithId();
			ALLog.d("账号" + localAccount.getUserName() + "密码"
					+ localAccount.getPassWord());
			invokeUIConnectXmppRequest(localAccount.getUserName(),
					localAccount.getPassWord(), isLoginWithId);
			break;
		case XMPP_THIRD_PART_CHECK_REGISTER_STATE_REQUEST:
			ALLog.d("ui請求檢測第三方登陸");
			invokeCheckThirdPartLoginRequest(event.getData());
			break;
		case XMPP_THIRD_PART_LOGIN_REQUEST:
			break;
		case XMPP_REGISTER_REQUEST:
			// invokeRegisterRequest(event.getData());
			invokeRegisterRequest(event.getData());
			break;
		case XMPP_CHECK_EMAIL_REQUEST:
			ALLog.d("ui請求檢測email");
			invokeCheckEmail(event.getData());
			break;
		case XMPP_LOGOUT_REQUEST:
			ALLog.d("ui请求退出登陆");
			invokeLogOutRequest();
			break;
		case XMPP_SEND_MESSAGE_REQUEST:
			// 发送Message消息
			invokeSendMessageRequest(event.getData());
			break;
		case XMPP_SEND_MESSAGE_RECEIPT_REQUEST:
			// 发送消息回执
			invokeSendMessageReceipt(event.getData());
			break;
		default:
			Object data = mALUiXmppRequestManager.getRequestXml(event);
			if (data == null) {
				ALLog.e("没有可处理" + event.getRequestTye() + "请求的方法");
				return;
			}
			mDefaultXmppAdapter.xmppSendXmppData(data);
			break;
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeDataConnectionConnected
	 * (com.alstudio.utils.android.net.ALConnectionManager.ALConnectionType)
	 */
	@Override
	public void invokeDataConnectionConnected(ALConnectionType type) {
		// TODO Auto-generated method stub
		isXmppAdapterValidate();
		isNoNetworkConnection = false;
		invokeDataConnectionConnectedEvent(type);
		// mDefaultXmppAdapter.

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeDataConnectionLoss()
	 */
	@Override
	public void invokeDataConnectionLoss() {
		// TODO Auto-generated method stub
		isXmppAdapterValidate();
		isNoNetworkConnection = true;
		ALLog.d("没有网络连接了");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.ALXmppConnectionEventCallback#onALEvent(com.
	 * alstudio.pojo.ALLocalData)
	 */
	@Override
	public void onALEvent(ALXmppEvent xmppLoginData) {
		// TODO Auto-generated method stub
		dispatchXmppEvent(xmppLoginData);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.alstudio.module.xmpp.distributor.distributor.
	 * CheckDistributorEventCallback
	 * #onALEvent(com.alstudio.module.xmpp.distributor
	 * .distributor.DistributorEvent)
	 */
	@Override
	public void onALEvent(DistributorEvent event) {
		// TODO Auto-generated method stub
		// 连接分发器回来的事件
		invokeGetDistributorEvent(event);
	}

	/**
	 * 处理发送message消息
	 * 
	 * @param obj
	 */
	private void invokeSendMessageRequest(Object obj) {
		ALMessage msg = (ALMessage) obj;
		if (mDefaultXmppAdapter != null) {
			if (mDefaultXmppAdapter.isLogined()) {
				mDefaultXmppAdapter.xmppSendMessage(msg);
			}
		}
	}

	/**
	 * 处理发送message回执
	 * 
	 * @param obj
	 */
	private void invokeSendMessageReceipt(Object obj) {

	}

	/**
	 * 处理退出登陆请求
	 */
	private void invokeLogOutRequest() {
		if (mDefaultXmppAdapter != null) {
			if (mDefaultXmppAdapter.isLogined()) {
				mDefaultXmppAdapter.xmppCleanConnection();
			}
		}
	}

	/**
	 * 处理检测Email是否可用
	 * 
	 * @param obj
	 */
	private void invokeCheckEmail(Object obj) {
		ALXmppData xmppLoginData = (ALXmppData) obj;

		CheckEmailIQCreator iq = new CheckEmailIQCreator(
				xmppLoginData.getEmail(), ALLocalEnv.getLocalEnv()
						.getVersionConfig().getServerInfo().getServerName());
		OpenStreamUtil.getDefaultUtil().startPostIq(xmppLoginData, iq,
				mDefaultXmppAdapter.getXmppListener());
	}

	/**
	 * 处理请求检测第三方账号注册状态
	 * 
	 * @param obj
	 */
	private void invokeCheckThirdPartLoginRequest(Object obj) {
		ALXmppData xmppLoginData = (ALXmppData) obj;
		CheckThirdPartLoginStateIQCreator iq = new CheckThirdPartLoginStateIQCreator(
				xmppLoginData);
		OpenStreamUtil.getDefaultUtil().startPostIq(xmppLoginData, iq,
				mDefaultXmppAdapter.getXmppListener());
	}

	/**
	 * 执行注册
	 * 
	 * @param obj
	 */
	private void invokeRegisterRequest(Object obj) {

		ALXmppData xmppLoginData = (ALXmppData) obj;

		RegisterIQCreator iq = new RegisterIQCreator(xmppLoginData);
		OpenStreamUtil.getDefaultUtil().startPostIq(xmppLoginData, iq,
				mDefaultXmppAdapter.getXmppListener());

	}

	/**
	 * 处理网络事件变化
	 * 
	 * @param type
	 */
	private void invokeDataConnectionConnectedEvent(ALConnectionType type) {
		ALLog.d("开始执行登陆");
		if (!isGetDistributorData) {

			// 还没有连接分发器
			ALLog.d("首先连接分发器");
			invokeCheckDistributor();
		} else {
			invokeReconnect(true, localAccount.getUserName(),
					localAccount.getPassWord(), "", true);
		}
	}

	/**
	 * 连接分发器
	 */
	private void invokeCheckDistributor() {
		VersionConfig config = ALLocalEnv.getLocalEnv().getVersionConfig();
		String ver = config.getAppVersion();
		// 连接两个分发器
		DistributorManager.getInstance().checkDistributor(ver, "Android",
				config.disp1, config.port, true);

		DistributorManager.getInstance().checkDistributor(ver, "Android",
				config.disp2, config.port, true);
	}

	/**
	 * 处理连接分发器后的业务逻辑，解析新版本更新或者强制更新。连接成功则用分发器下发的IM地址，否则用缺省地址。如果有账号则直接登陆，否则直接返回
	 * 
	 * @param event
	 */
	private synchronized void invokeGetDistributorEvent(DistributorEvent event) {
		ServerInfo info = event.getCheckedServerInfo();

		if (info != null) {
			ALLog.d("检测分发器成功");
			if (isGetDistributorData) {
				ALLog.d("已经连接过分发器，不需要再连");
				return;
			}
			isGetDistributorData = true;

			ALLocalEnv.getLocalEnv().getVersionConfig().setServerInfo(info);
			// 用于测试
			ServerInfo curLocalInfo = ALLocalEnv.getLocalEnv()
					.getVersionConfig().getServerInfo();

			ALLog.d("当前IM服务器地址: " + curLocalInfo.getIMServerIP() + " 版本信息 ");

			if (!TextUtils.isEmpty(curLocalInfo.getLatestVer())) {
				// 有版本更新啦
				ALLog.d("有版本更新啦!" + curLocalInfo.getLatestVer() + " 更新内容: "
						+ curLocalInfo.getWhatsNew());
			}

			// 首先检测新版本信息
			if (curLocalInfo.isForceUpdate()) {
				// 强制更新，不能登陆!
				ALLog.d("强制更新，不能登陆!");
				return;
			}

			if (TextUtils.isEmpty(localAccount.getUserName())
					&& TextUtils.isEmpty(localAccount.getPassWord())) {
				ALLog.d("没有账号信息，不做登陆");
				return;
			}

			// 保存当前服务器配置到数据库
			LocalConfigure configure = new LocalConfigure();
			configure.setServerInfo(info);
			ALLocalEnv.getLocalEnv().getDatabase()
					.saveLocalConfigure(configure);
			ALLog.d("分发器下发的服务配置已更新到数据库");

			invokeReconnect(true, localAccount.getUserName(),
					localAccount.getPassWord(), "", true);
			// invokeReconnect(true, localAccount.getUserName(),
			// localAccount.getPassWord(), "", true);
			// invokeReconnect(true, localAccount.getUserName(),
			// localAccount.getPassWord(), "", true);

		} else {
			// 无法连接到分发器
			ALLog.e("无法连接到分发器，使用缺省地址");
			isGetDistributorData = true;
			invokeReconnect(true, localAccount.getUserName(),
					localAccount.getPassWord(), "", true);
		}

	}

	/**
	 * 处理重连服务器的请求
	 * 
	 * @param isSystemType
	 *            true表示用系统账号登陆
	 * @param user
	 *            用户名
	 * @param pwd
	 *            密码
	 * @param callingName
	 *            调用者
	 * @param loginNow
	 *            true表示马上登陆，false表示需要判断是否需要加入到重连队列
	 * @author Alonso Lee
	 */
	protected synchronized void invokeReconnect(boolean isSystemType,
			String user, String pwd, String callingName, boolean loginNow) {

		if (isSystemType) {
			ALLog.d("系统账号登陆，ID为 " + user + " 密码为 " + pwd);
			mReconnectHandler.sendEmptyMessageDelayed(RECONNECT_TO_IM_SERVER,
					LOGIN_IM_SERVER_TIME_OUT);

		} else {
			// 如果是自定义账号登陆的，那么不需要重连
			ALLog.d("使用自定义账号登陆，不需要重连");
		}

		if (mDefaultXmppAdapter.xmppCheckLoginState() == ALXmppConnectionState.XMPP_STATE_IDLE) {
			// 直接重连
			ALLog.d("当前没有在连接，马上开始重连！调用处:" + callingName);
			invokeUIConnectXmppRequest(user, pwd, isSystemType);
		} else {
			ALLog.w("当前还在连接服务器,正在断开当前连接...");

			// 先把当前的连接关掉
			mDefaultXmppAdapter.xmppCleanConnection();
		}
	}

	/**
	 * 处理登录XMPP服务器的请求
	 * 
	 * @author Alonso Lee
	 */
	public synchronized void invokeUIConnectXmppRequest(String username,
			String pwd, boolean authType) {
		if (isNoNetworkConnection) {
			ALLog.d("当前没有可用网络！");
			isLoginWithId = false;
			return;
		}

		// 如果已经连接分发器了，那么开始重连
		if (isGetDistributorData) {

			if (ALLocalEnv.getLocalEnv().getVersionConfig().getServerInfo()
					.isForceUpdate()) {
				ALLog.d("强制更新啊，不准登陆");
				return;
			}

			if (authType) {
				// 如果使用系统账号登陆，并且用户已经注销出去了，那么不用重连
				if (localAccount.isLogoff() && !isLoginWithId) {
					ALLog.d("已经注销出去了，你又用系统账号登陆吗？");
					cleanReconnectRequest();
					return;
				}
			}
			if (!TextUtils.isEmpty(username) && !TextUtils.isEmpty(pwd)) {

				mReconnectHandler.removeMessages(RECONNECT_TO_IM_SERVER);

				ALXmppData xmppLoginData = ALLocalEnv.getLocalEnv()
						.createALXmppData();
				xmppLoginData.setUsername(username);
				xmppLoginData.setPassword(pwd);
				String type = "system";
				/* 设定验证类型 */
				if (!authType) {
					type = "email";
				}

				xmppLoginData.setAuthType(type);
				// 开始登陆
				ALLocalEnv.adapter.xmppLogin(xmppLoginData);
			}

		} else {
			// 否则连接分发器
			ALLog.d("首先连接分发器...");
			invokeCheckDistributor();
		}
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeC2SThreadReconnectRequest()
	 */
	@Override
	public void invokeC2SThreadReconnectRequest() {
		// TODO Auto-generated method stub
//		invokeReconnect(true, localAccount.getUserName(),
//				localAccount.getPassWord(), "invokeC2SThreadReconnectRequest", true);
		sendReconnectRequest(true);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeConnectionLost(com.alstudio.pojo.ALLocalData)
	 */
	@Override
	protected void invokeConnectionLost(ALXmppEvent data) {
		// TODO Auto-generated method stub

		isLoginWithId = false;
		if (mDefaultXmppAdapter.xmppCheckLoginState() == ALXmppConnectionState.XMPP_STATE_CONNECTION_ESTABLISHED) {
			// 已经登录，不搞了
			ALLog.d("当前已经登录了，不要执行重连");
			return;
		}

		ALLog.d("连接已丢失");

		// isReconnecting = true;

		if (data.getErrorMessage().equals("conflict")) {

			String conflictSid = data.getConflictId();

			if (!TextUtils.isEmpty(conflictSid)) {
				if (conflictSid.equals(curXmppSessionId)) {

					ALLog.d("被踢下线了。冲突的session id是" + data.getConflictId());
					ALXmppEvent conflictEvent = new ALXmppEvent(
							ALXmppEventType.XMPP_CONFILICT_LOGIN_EVENT);
					conflictEvent.setErrorMessage(data.getConflictId());
					ALEventDeliver.getDefaultAlEventDeliver().postALEvent(
							conflictEvent);
					return;
				}
			}
		}

		// 如果不是因为用户注销登录，那么需要重连
		if (!localAccount.isLogoff()) {
			ALLog.d("连接已断开" + data.getErrorMessage());

			if (mDefaultXmppAdapter.xmppCheckLoginState() == ALXmppConnectionState.XMPP_STATE_IDLE) {

				if (!TextUtils.isEmpty(localAccount.getUserName())) {
					sendReconnectRequest(false);
				} else {
					ALLog.d("账号都没有,登陆个甚");
				}
			}
		}

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeConnectionEstablished(com.alstudio.pojo.ALLocalData)
	 */
	@Override
	protected void invokeConnectionEstablished(ALXmppEvent data) {
		// TODO Auto-generated method stub
		isLoginWithId = false;
		// 连接成功,开启C2S心跳包线程
		invokeStartC2sPing();

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeConnectionAuthFailed(com.alstudio.pojo.ALLocalData)
	 */
	@Override
	protected void invokeConnectionAuthFailed(ALXmppEvent data) {
		// TODO Auto-generated method stub

	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * invokeUpdateXmppSessionId(com.alstudio.pojo.ALLocalData)
	 */
	@Override
	protected void invokeUpdateXmppSessionId(ALXmppEvent data) {
		// TODO Auto-generated method stub
		curXmppSessionId = data.getCurXmppSessionId();
		ALLog.d("更新xmpp连接会话ID " + curXmppSessionId);
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.alstudio.module.xmpp.EventHandler.network.BaseALXmppLoginWrapper#
	 * dispatchXmppEvent(com.alstudio.pojo.ALLocalData)
	 */
	@Override
	protected void dispatchXmppEvent(ALXmppEvent data) {
		// TODO Auto-generated method stub
		ALLog.d("接收到 XMPP事件: " + data.getType());
		switch (data.getType()) {
		case XMPP_CONNECTION_ESTABLISHED_EVENT:
			// 连接成功
			invokeConnectionEstablished(data);
			break;
		case XMPP_AUTH_FAILED_EVENT:
			// 账号验证失败
			invokeConnectionAuthFailed(data);
			break;
		case XMPP_CONNECTION_LOST_EVENT:
			// 连接丢失
			invokeConnectionLost(data);
			break;
		case XMPP_CONNECTION_STATE_CHANGED_EVENT:
			// 连接状态改变
			break;
		case XMPP_LOGOUT_SUCCESS_EVENT:
			// 注销
			break;
		case XMPP_UPDATE_XMPP_SESSION_ID_EVENT:
			invokeUpdateXmppSessionId(data);
			break;
		case XMPP_C2S_PING_RESPONSE_EVENT:
			// 清除挂起的c2s心跳
			invokeC2sResponseEvent();
			break;
		default:
			break;
		}

	}

}